﻿using System;
using System.Diagnostics;
using Nature.Numerics;
namespace Nature
{
    /// <summary>
    /// Chemical Kinetics
    /// </summary>
    public interface IChemicalKinetics
    {
        /// <summary>
        /// Number of species
        /// </summary>
        int Nsp { get; }

        /// <summary>
        /// Number of chemical reactions
        /// </summary>
        int Nre { get; }

        /// <summary>
        /// Number of explicit temperature dependencies
        /// </summary>
        int Ntd { get; }

        /// <summary>
        /// Calculates explicit temperature dependencies
        /// </summary>
        void CalcReactionExplicitTemperatureDependencies(IdealGasMixture mixture, double[] expTDep);

        /// <summary>
        /// Computes reaction rate forward constants
        /// </summary>
        void CalcReactionForwardConstants(IdealGasMixture mixture, double[] fwd);

        /// <summary>
        /// Computes reaction rate reverse constants
        /// </summary>
        void CalcReactionReverseConstants(IdealGasMixture mixture, double[] rev);

        /// <summary>
        /// Computes forward and reverse reaction rates [mol/m**3/sec]
        /// </summary>
        void CalcReactionForwardRates(IdealGasMixture mixture, double[] forwardRate);

        /// <summary>
        /// Computes reverse reaction rates [mol/m**3/sec]
        /// </summary>
        void CalcReactionReverseRates(IdealGasMixture mixture, double[] reverseRate);

        /// <summary>
        /// Computes species chemical sources [mol/m**3/sec]
        /// </summary>
        void CalcSpeciesCreationRates(IdealGasMixture mixture, double[] creationRate);

        /// <summary>
        /// Computes species chemical sources [mol/m**3/sec]
        /// </summary>
        void CalcSpeciesDestructionRates(IdealGasMixture mixture, double[] destructionRate);
    }

    public static partial class ITolerance
    {
        /// <summary>
        /// Computes chemical reaction rates [mol/m**3/sec]
        /// </summary>
        public static void CalcChemicalReactionRates(this IChemicalKinetics ck, IdealGasMixture mixture, double[] rate)
        {
            //var fwd = mixture.rat;
            //var rev = mixture.CkReverseReactionRates;

            //for (int ire = 0; ire < ck.Nre; ++ire)
            //{
            //    rate[ire] = fwd[ire] - rev[ire];
            //}
        }

        /// <summary>
        /// Computes species chemical sources [mol/m**3/sec]
        /// </summary>
        public static void CalcSpeciesNetProductionRate(this IChemicalKinetics ck, IdealGasMixture mixture, double[] rate)
        {
            var fwd = mixture.SpeciesChemicalCreationRates;
            var rev = mixture.SpeciesChemicalDestructionRates;

            for (int isp = 0; isp < mixture.Nsp; ++isp)
            {
                rate[isp] = fwd[isp] - rev[isp];
            }
        }

    }

    public class ChemicalKineticsNullObject : IChemicalKinetics
    {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private int m_nsp;

        public ChemicalKineticsNullObject(int nsp) { m_nsp = nsp; }

        public ChemicalKineticsNullObject(ModelObject context) { m_nsp = context.Nsp; }


        /// <summary>
        /// Number of species
        /// </summary>
        public int Nsp { get { return m_nsp; } }


        /// <summary>
        /// Number of chemical reactions
        /// </summary>
        public int Nre { get { return 0; } }


        /// <summary>
        /// Number of explicit temperature dependencies
        /// </summary>
        public int Ntd { get { return 0; } }


        /// <summary>
        /// Calculates explicit temperature dependencies
        /// </summary>
        public void CalcReactionExplicitTemperatureDependencies(IdealGasMixture mixture, double[] expTDep) { }


        /// <summary>
        /// Computes reaction rate forward and reverse constants
        /// </summary>
        public void CalcReactionForwardConstants(IdealGasMixture mixture, double[] fwd) { }

        /// <summary>
        /// Computes reaction rate forward and reverse constants
        /// </summary>
        public void CalcReactionReverseConstants(IdealGasMixture mixture, double[] rev) { }


        /// <summary>
        /// Computes forward and reverse reaction rates [mol/m**3/sec]
        /// </summary>
        public void CalcReactionForwardRates(IdealGasMixture mixture, double[] fwd) { }


        /// <summary>
        /// Computes forward and reverse reaction rates [mol/m**3/sec]
        /// </summary>
        public void CalcReactionReverseRates(IdealGasMixture mixture, double[] rev) { }


        /// <summary>
        /// Computes species chemical sources [mol/m**3/sec]
        /// </summary>
        public void CalcSpeciesCreationRates(IdealGasMixture mixture, double[] productionRate) { }

        /// <summary>
        /// Computes species chemical sources [mol/m**3/sec]
        /// </summary>
        public void CalcSpeciesDestructionRates(IdealGasMixture mixture, double[] consumptionRate) { }
    }


    class ChemicalKineticsTabulated : IChemicalKinetics
    {
        public readonly IChemicalKinetics InnerIChemicalKinetics;
        private Tabulated m_expTemp;

        internal ChemicalKineticsTabulated(IChemicalKinetics originalChemicalKinetics)
        {
            this.InnerIChemicalKinetics = originalChemicalKinetics;
            Nsp = originalChemicalKinetics.Nsp;
        }

        #region IChemicalKinetics Members

        public int Nsp
        {
            get;
            private set;
        }

        public int Nre
        {
            get;
            private set;
        }

        public int Ntd
        {
            get;
            private set;
        }

        void IChemicalKinetics.CalcReactionExplicitTemperatureDependencies(IdealGasMixture mixture, double[] expTDep)
        {
            if (m_expTemp != null)
            {
                m_expTemp.Approximate(expTDep, mixture.Temperature);
            }
            else
            {
                lock (this)
                {
                    var igm = mixture.Model.CreateIdealGasMixture(mixture.Model.SpeciesIDs[0]);
                    VectorFunctionDelegate func = (_dep, _temp) =>
                    {
                        igm.UpdateTP(_temp, Constants.Atmosphere);
                        InnerIChemicalKinetics.CalcReactionExplicitTemperatureDependencies(igm, _dep);
                    };
                    m_expTemp = m_expTemp ?? new Tabulated(null, 0, 10000.0, 0.01);
                }
                m_expTemp.Approximate(expTDep, mixture.Temperature);
            }
        }

        void IChemicalKinetics.CalcReactionForwardConstants(IdealGasMixture mixture, double[] fwd)
        {
            InnerIChemicalKinetics.CalcReactionForwardConstants(mixture, fwd);
        }

        void IChemicalKinetics.CalcReactionReverseConstants(IdealGasMixture mixture, double[] rev)
        {
            InnerIChemicalKinetics.CalcReactionReverseConstants(mixture, rev);
        }

        void IChemicalKinetics.CalcReactionForwardRates(IdealGasMixture mixture, double[] forwardRate)
        {
            InnerIChemicalKinetics.CalcReactionForwardRates(mixture, forwardRate);
        }

        void IChemicalKinetics.CalcReactionReverseRates(IdealGasMixture mixture, double[] reverseRate)
        {
            InnerIChemicalKinetics.CalcReactionReverseRates(mixture, reverseRate);
        }

        void IChemicalKinetics.CalcSpeciesCreationRates(IdealGasMixture mixture, double[] creationRate)
        {
            InnerIChemicalKinetics.CalcSpeciesCreationRates(mixture, creationRate);
        }

        void IChemicalKinetics.CalcSpeciesDestructionRates(IdealGasMixture mixture, double[] destructionRate)
        {
            InnerIChemicalKinetics.CalcSpeciesDestructionRates(mixture, destructionRate);
        }

        #endregion
    }
}
